package com.vichat.common.ffmpeg.util;

import com.vichat.common.ffmpeg.cmd.CmdExecuter;
import com.vichat.common.ffmpeg.cmd.IStringGetter;
import com.vichat.common.util.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by ranjx on 2017/3/17.
 * FFMpegUntil
 * FFMpeg工具类
 * 本类封装FFMpeg对音视频的操作
 */
public class FFMpegUtil implements IStringGetter {
    protected static final Logger logger = LoggerFactory.getLogger(FFMpegUtil.class);
    private int runtime = 0;
    private String ffmpegUri;//ffmpeg地址
    private String originFileUri; //视频源文件地址
    private enum FFMpegUtilStatus { Empty, CheckingFile, GettingRuntime };
    private FFMpegUtilStatus status = FFMpegUtilStatus.Empty;

    /**
     * 构造函数
     * @param ffmpegUri ffmpeg的全路径
     * 如e:/ffmpeg/ffmpeg.exe 或 /root/ffmpeg/bin/ffmpeg
     * @param originFileUri 所操作视频文件的全路径
     * 如e:/upload/temp/test.wmv
     */
    public FFMpegUtil( String ffmpegUri, String originFileUri ){
        this.ffmpegUri = ffmpegUri;
        this.originFileUri = originFileUri;
    }

    /**
     * 获取视频时长
     * @return
     */
    public int getRuntime(){
        runtime = 0;
        status = FFMpegUtilStatus.GettingRuntime;
        cmd.clear();
        cmd.add(ffmpegUri);
        cmd.add("-i");
        cmd.add(originFileUri);
        CmdExecuter.exec(cmd, this);
        return runtime;
    }

    /**
     * 检测文件是否是支持的格式
     * 将检测视频文件本身，而不是扩展名
     * @return
     */
    public boolean isSupported(){
        isSupported = true;
        status = FFMpegUtilStatus.CheckingFile;
        cmd.clear();
        cmd.add(ffmpegUri);
        cmd.add("-i");
        cmd.add(originFileUri);
        CmdExecuter.exec(cmd, this);
        return isSupported;
    }

    private boolean isSupported;

    /**
     * 生成视频截图
     * @param imageSavePath 截图文件保存全路径
     * @param screenSize 截图大小 如640x480
     */
    public void makeScreenCut( String imageSavePath , String screenSize ){
        cmd.clear();
        cmd.add(ffmpegUri);
        cmd.add("-i");
        cmd.add(originFileUri);
        cmd.add("-y");
        cmd.add("-f");
        cmd.add("image2");
        cmd.add("-ss");
        cmd.add("8");
        cmd.add("-t");
        cmd.add("0.001");
        cmd.add("-s");
        cmd.add(screenSize);
        cmd.add(imageSavePath);
        logger.info("生成视频截图指令："+cmd.toString());
        CmdExecuter.exec(cmd, null);
    }

    /**
     * 视频转换
     * @param fileSavePath 文件保存全路径（包括扩展名）如 e:/abc/test.flv
     * @param screenSize 视频分辨率 如640x480
     * @param audioByte 音频比特率
     * @param audioCollection 音频采样率
     * @param quality 视频质量(0.01-255)越低质量越好
     * @param fps 每秒帧数（15或29.97）
     */
    public void videoTransfer(
            String fileSavePath,
            String screenSize,
            int audioByte,
            int audioCollection,
            double quality,
            double fps ){
        cmd.clear();
        cmd.add(ffmpegUri);
        cmd.add("-i");
        cmd.add(originFileUri);
        cmd.add("-y");
        cmd.add("-ab");
        cmd.add( Integer.toString(audioByte) );
        cmd.add("-ar");
        cmd.add( Integer.toString(audioCollection) );
        cmd.add("-qscale");
        cmd.add( Double.toString(quality) );
        cmd.add("-r");
        cmd.add( Double.toString(fps) );
        cmd.add("-s");
        cmd.add(screenSize);
        cmd.add( fileSavePath );
        logger.info("视频转换指令："+cmd.toString());
        CmdExecuter.exec(cmd, null);
    }

    /**
     * 音频转换
     * @param fileSavePath 文件保存全路径（包括扩展名）如 e:/abc/test.mp3
     */
    public void audioTransfer(String fileSavePath){
        cmd.clear();
        cmd.add(ffmpegUri);
        cmd.add("-i");
        cmd.add(originFileUri);
        cmd.add("-acodec");
        cmd.add("libmp3lame");
        cmd.add( fileSavePath );
        logger.info("音频转换指令："+cmd.toString());
        CmdExecuter.exec(cmd, null);
    }

    /**
     * 音频转换
     * @param fileSavePath 文件保存全路径（包括扩展名）如 e:/abc/test.mp3
     */
    public void audioToMp3(String fileSavePath){
        Runtime run = null;
        try {
            run = Runtime.getRuntime();
            long start=System.currentTimeMillis();
            Process p=run.exec(ffmpegUri + " -i " + originFileUri + " -acodec libmp3lame " + fileSavePath);//执行ffmpeg.exe,前面是ffmpeg.exe的地址，中间是需要转换的文件地址，后面是转换后的文件地址。-i是转换方式，意思是可编码解码，mp3编码方式采用的是libmp3lame
            //释放进程
            p.getOutputStream().close();
            p.getInputStream().close();
            p.getErrorStream().close();
            p.waitFor();
            long end=System.currentTimeMillis();
            System.out.println(fileSavePath+" convert success, costs:"+(end-start)+"ms");
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //run调用lame解码器最后释放内存
            run.freeMemory();
        }
    }


    /**
     * 音频转换
     * @param fileNameNoEx 文件保存全路径（包括扩展名）如 e:/abc/test.mp3
     */
    public static void datToMp4(String url,String fileNameNoEx){
        try {
            String fileName = fileNameNoEx + "_" + NumberUtils.getNumSmallCharRandom(10);

            cmd.clear();
            cmd.add("ndserver");
            cmd.add("-cmd");
            cmd.add("mux");
            cmd.add("-i");
            cmd.add( url + fileNameNoEx + ".dat");
            cmd.add("-o");
            cmd.add( url + fileName + ".mp4" );
            logger.info("datToMp4："+cmd.toString());
            CmdExecuter.exec(cmd, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 音频转换
     * @param fileName 文件保存全路径（包括扩展名）如 e:/abc/test.mp3
     */
    public static void mp4Towav(String url,String fileName){
        try {
            cmd.clear();
            cmd.add("/usr/local/ffmpeg/ffmpeg");
            cmd.add("-i");
            cmd.add( url + fileName + ".mp4");
            cmd.add("-f");
            cmd.add("wav");
            cmd.add( url + fileName + ".wav" );
            logger.info("mp4Towav："+cmd.toString());
            CmdExecuter.exec(cmd, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 音频转换
     * @param fileName 文件保存全路径（包括扩展名）如 e:/abc/test.mp3
     */
    public static void mp4Tomp3(String url,String fileName){
        try {
            String cmd = "/usr/local/ffmpeg/ffmpeg -i "+ url + fileName + ".mp4 -f mp3 -acodec libmp3lame -y " + url + fileName + ".mp3";
            java.lang.Runtime rt = Runtime.getRuntime();

            Process proc = rt.exec(cmd);
            InputStream stderr = proc.getErrorStream();
            InputStreamReader isr = new InputStreamReader(stderr);
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            StringBuffer sb = new StringBuffer();
            while ((line = br.readLine()) != null){
                sb.append(line);
            }
            logger.info("mp4Tomp3："+cmd.toString());
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage(),e);
        }
    }

    private static List<String> cmd = new ArrayList<String>();

    @Override
    public void dealString( String str ){

        switch( status )
        {
            case Empty:
                break;
            case CheckingFile:{
                Matcher m = Pattern.compile("Unknown format").matcher(str);
                if( m.find() )
                    this.isSupported = false;
                break;
            }
            case GettingRuntime:{
                Matcher m = Pattern.compile("Duration: //w+://w+://w+").matcher(str);
                while (m.find())
                {
                    String msg = m.group();
                    msg = msg.replace("Duration: ", "");
                    //runtime = TimeUtil.runtimeToSecond(msg);
                }
                break;
            }
        }
    }

    public static void main(String[]args) {
//        FFMpegUtil ffMpegUtil = new FFMpegUtil("d:/ffmpeg/bin/ffmpeg.exe","d:/file/67f6da62-dffb-4e51-860e-f8fd78aae1e6.caf");
//        ffMpegUtil.audioTransfer("d:/file/1.mp3");
        FFMpegUtil.datToMp4("/Users/zain/Documents/recFile/", "1234567810");
    }

}
